package com.lxw.manage_media.service;

import com.alibaba.fastjson.JSON;
import com.lxw.framework.domain.media.MediaFile;
import com.lxw.framework.domain.media.request.QueryMediaFileRequest;
import com.lxw.framework.domain.media.response.CheckChunkResult;
import com.lxw.framework.domain.media.response.MediaCode;
import com.lxw.framework.exception.CustomException;
import com.lxw.framework.model.response.CommonCode;
import com.lxw.framework.model.response.QueryResponseResult;
import com.lxw.framework.model.response.QueryResult;
import com.lxw.framework.model.response.ResponseResult;
import com.lxw.manage_media.dao.MediaFileRepository;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

@Service
public class MediaUploadServiceImpl implements IMediaUploadService {
    @Value("${yh-service-manage-media.upload-location}")
    private String locationRoot;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    MediaFileRepository mediaFileRepository;
    @Value("${yh-service-manage-media.mq.routingkey‐media‐video}")
    public  String routingkey_media_video;
    @Override
    public ResponseResult register(String fileMd5, String fileName, Long fileSize, String mimetype, String fileExt) {
        //一 检测文件是否存在

       // 1. 规定我们文件目录结构
        /**
         * * 规则：
         * * 一级目录：md5的第一个字符
         * * 二级目录：md5的第二个字符
         * * 三级目录：md5
         * 文件名：md5+文件扩展名
         */
        String filePath = locationRoot+fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/";
        String fileNameNew = fileMd5+"."+fileExt;
        File file = new File(filePath+fileNameNew);

        // 根据fileMd5查询文件信息
        Optional<MediaFile> byId = mediaFileRepository.findById(fileMd5);

        if(file.exists()&&byId.isPresent()){
            throw new CustomException(MediaCode.UPLOAD_FILE_REGISTER_EXIST);
        }
        // 二 检测文件夹是否存在
        File fileFloder = new File(filePath);
        if(!fileFloder.exists()){
            fileFloder.mkdirs();
        }


        return new ResponseResult(CommonCode.SUCCESS);
    }
private String chunks="chunks";
    @Override
    public CheckChunkResult checkchunk(String fileMd5, Integer chunk, Integer chunkSize) {
        /**
         * * 规则：
         * * 一级目录：md5的第一个字符
         * * 二级目录：md5的第二个字符
         * * 三级目录：md5
         * 文件名：md5+文件扩展名
         */
        String filePath = locationRoot+fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/"+chunks+"/";
        String fileName = String.valueOf(chunk);

        File file = new File(filePath + fileName);
        if(file.exists()&&chunkSize==file.length()){
            return new CheckChunkResult(MediaCode.CHUNK_FILE_EXIST_CHECK,true);
        }else {
            return new CheckChunkResult(CommonCode.SUCCESS,false);
        }

    }

    @Override
    public ResponseResult uploadchunk(MultipartFile file, Integer chunk, String fileMd5) {
        if(file==null){
            // 文件不存在
            throw new CustomException(MediaCode.MERGE_FILE_FAIL);
        }

        // 存放文件的目录
        /**
         * * 规则：
         * * 一级目录：md5的第一个字符
         * * 二级目录：md5的第二个字符
         * * 三级目录：md5
         * 文件名：md5+文件扩展名
         */
        String filePath = locationRoot+fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/"+chunks+"/";
        File file2 = new File(filePath);
        if(!file2.exists()){
            file2.mkdirs();
        }

        FileOutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            File file1 = new File(filePath + chunk);
            file1.createNewFile();

            // 写文件
            outputStream = new FileOutputStream(file1);
            inputStream = file.getInputStream();
            IOUtils.copy(inputStream,outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }



        return new ResponseResult(CommonCode.SUCCESS);
    }

    @Override
    public ResponseResult mergechunks(String fileMd5, String fileName, Long fileSize, String mimetype, String fileExt) {
        // 生成文件路径
        String filePath = locationRoot+fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/";
        String fileNameNew = fileMd5+"."+fileExt;
        File file = new File(filePath+fileNameNew);
        if(file.exists()){
            file.delete();
        }
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 分片的路径
        String chunksPath = locationRoot+fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/"+chunks+"/";
        File chunksFloder = new File(chunksPath);

        mergeFiles(file,chunksFloder);

        MediaFile mediaFile = new MediaFile();
        mediaFile.setFileId(fileMd5);
        mediaFile.setFileName(fileMd5+"."+fileExt);
        mediaFile.setFileOriginalName(fileName);
        mediaFile.setFilePath(fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/");
        mediaFile.setFileSize(fileSize);
        mediaFile.setMimeType(mimetype);
        mediaFile.setFileUrl(fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/"+fileMd5+"."+fileExt);
        mediaFile.setUploadTime(new Date());
        mediaFile.setFileType(fileExt);
        //状态为上传成功
        mediaFile.setFileStatus("301002");
        MediaFile save = mediaFileRepository.save(mediaFile);


        // 视频转码
        Map<String,String> map = new HashMap<>();
        map.put("mediaId",fileMd5);
        rabbitTemplate.convertAndSend("ex_media_processor",routingkey_media_video, JSON.toJSONString(map));
        return new ResponseResult(CommonCode.SUCCESS);
    }

    @Override
    public QueryResponseResult findList(Integer page, Integer pageSize, QueryMediaFileRequest qpr) {
        MediaFile mediaFile = new MediaFile();
        if(StringUtils.isNotBlank(qpr.getFileOriginalName())){
            mediaFile.setFileOriginalName(qpr.getFileOriginalName());
        }
        if(StringUtils.isNotBlank(qpr.getProcessStatus())){
            mediaFile.setProcessStatus(qpr.getProcessStatus());
        }
        if(StringUtils.isNotBlank(qpr.getTag())){
            mediaFile.setTag(qpr.getTag());
        }
        // 查询条件
        Example<MediaFile> example = Example.of(mediaFile);

        // 分页组装器
        // 页码是从0 开始
        page --;
        PageRequest of = PageRequest.of(page, pageSize);

        Page<MediaFile> all = mediaFileRepository.findAll(example, of);

        QueryResult<MediaFile> queryResult = new QueryResult();
        queryResult.setTotal(all.getTotalElements());
        queryResult.setList(all.getContent());
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);
    }

    @Override
    public ResponseResult process(String mediaId) {
        // 视频转码
        Map<String,String> map = new HashMap<>();
        map.put("mediaId",mediaId);
        rabbitTemplate.convertAndSend("ex_media_processor",routingkey_media_video, JSON.toJSONString(map));
        return new ResponseResult(CommonCode.SUCCESS);
    }

    private void mergeFiles(File writefile,File chunkFiles){
        try {
            RandomAccessFile fileWrite = new RandomAccessFile(writefile,"rw");
            fileWrite.seek(0);//指针指向文件最顶部
            //缓冲区
            byte[] b = new byte[1024];
            File[] files = chunkFiles.listFiles();
            List<File> fileList = new ArrayList<>(Arrays.asList(files));
            // 文件排序从小到大
            Collections.sort(fileList, new Comparator<File>() {

                @Override
                public int compare(File o1, File o2) {
                    if(Integer.parseInt(o1.getName())<Integer.parseInt(o2.getName())){
                        return -1;
                    }
                    return 1;
                }
            });

            for (File file:fileList) {
                RandomAccessFile fileRead = new RandomAccessFile(file,"rw");
                int len = -1;// -1代表度文件结束
                while ((len = fileRead.read(b))!=-1){
                    fileWrite.write(b,0,len);
                }
                fileRead.close();

            }

            fileWrite.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            boolean file1 = chunkFiles.isDirectory();
            if(file1){
                File[] files =  chunkFiles.listFiles();
                for (File file:files) {
                    file.delete();
                }
                chunkFiles.delete();
            }else{
                chunkFiles.delete();
            }

        }


    }

}
